#include "pdeFile.h"
#include <algorithm>
#include <sstream>
#include <fstream>
#include <time.h>
#include <stack>
#include <sys/stat.h>
#include <iomanip>

#include <windows.h>
#include <direct.h>
#include <sys/utime.h>

#include <assert.h>
#include <Shlwapi.h>
#include "volume_utils.h"

namespace pde{
	const std::string PATH_SEPARATORS = "/\\";

	std::string GetTagValue(const std::string& buffer, const char* tag)
	{
		size_t stringPos = buffer.find(tag);
		if (stringPos == std::string::npos)
		{
			return "";
		}

		size_t pos2 = buffer.find("=", stringPos);
		if (pos2 == std::string::npos)
		{
			pos2 = buffer.find(":", stringPos);
		}

		if (pos2 == std::string::npos)
		{
			return "";
		}

		size_t posend = buffer.find('\r', pos2);
		if (posend == std::string::npos)
		{
			posend = buffer.find('\n', pos2);
		}

		// Get the element data filename
		std::string value = "";
		bool firstspace = true;
		size_t index = pos2 + 1;
		while (index < buffer.size()
			&& buffer[index] != '\r'
			&& buffer[index] != '\n'
			)
		{
			if (buffer[index] != ' ')
			{
				firstspace = false;
			}
			if (!firstspace)
			{
				value += buffer[index];
			}
			index++;
		}

		return value;
	}


	std::string replaceAllCharacters(const std::string& name, const char oldChar, const char newChar)
	{
		// the simplest algorithm but it should be fast enough
		//
		std::string conv(name);
		for (size_t i = 0; i < conv.size(); ++i) {
			if (conv[i] == oldChar)
				conv[i] = newChar;
		}
		return conv;
	}


	bool dirExists(const std::string& dirpath)
	{
		DWORD result = GetFileAttributesA(dirpath.c_str());
		return (result != INVALID_FILE_ATTRIBUTES) && (result & FILE_ATTRIBUTE_DIRECTORY);
	}

	std::string fileName(const std::string& filepath)
	{
		std::string::size_type separator = filepath.find_last_of("/\\");
		if (separator != std::string::npos)
			return filepath.substr(separator + 1);
		else
			return filepath;
	}

	std::string baseName(const std::string& filepath)
	{
		std::string filename = fileName(filepath);
		std::string::size_type dot = filename.rfind(".");

		if (dot != std::string::npos)
			return filename.substr(0, dot);
		else
			return filename;
	}

	std::string fullBaseName(const std::string& filepath)
	{
		std::string::size_type dot = filepath.rfind(".");

		if (dot != std::string::npos)
			return filepath.substr(0, dot);
		else
			return filepath;
	}

	std::string dirName(const std::string& filepath)
	{
		if (dirExists(filepath)) //< directory passed
			return filepath;

		std::string::size_type separator = filepath.find_last_of("/\\");
		if (separator != std::string::npos)
			return filepath.substr(0, separator);
		else
			return "";
	}

	std::string  cleanupPath(std::string path, bool native /*= true*/)
	{

		if (path.empty())
			return "";

		// remove double path separators
		std::string::size_type p_start = 0;
		// do not convert windows network path prefix "\\", if on windows
		if (path.length() >= 2 && path.substr(0, 2) == "\\\\")
			p_start = 2;
		std::string::size_type p = p_start;
		while (p != std::string::npos) {
			std::string::size_type p_next;
			p_next = path.find("//", p);
			if (p_next == std::string::npos)
				p_next = path.find("\\\\", p);
			if (p_next == std::string::npos)
				p_next = path.find("\\/", p);
			if (p_next == std::string::npos)
				p_next = path.find("/\\", p);

			if (p_next != std::string::npos)
				path = path.substr(0, p_next) + path.substr(p_next + 1);

			p = p_next;
		}

		// remove trailing separator
		if (path.find_last_of(PATH_SEPARATORS) == path.size() - 1)
			path = path.substr(0, path.size() - 1);

		// convert to win or unix separators
		bool convertToWin = native;
		if (convertToWin) {
			// convert to native windows separators
			path = replaceAllCharacters(path, '/', '\\');

			// convert drive letter to uppercase
			if ((path.size() > 1) && isalpha(path[0]) && (path[1] == ':'))
				std::transform(path.begin(), path.begin() + 1, path.begin(), toupper);
		}
		else {
			// convert to unix separators
			assert(p_start < path.length()); // see above
			path = path.substr(0, p_start) + replaceAllCharacters(path.substr(p_start), '\\', '/');
		}

		return path;
	}


	std::string combine(const std::string& dir, const std::string& filename)
	{
		return cleanupPath(dir + (filename.empty() ? "" : "/" + filename), true);
	}
	}

